package com.cis467.mrball.parts;

import java.util.ArrayList;



public class Level {

	public static final int FLOOR_COLS = 12;
	public static final int FLOOR_ROWS = 9;
	public static final int HWALL_COLS = FLOOR_COLS; 
	public static final int HWALL_ROWS = FLOOR_ROWS + 1;
	public static final int VWALL_COLS = FLOOR_COLS + 1;
	public static final int VWALL_ROWS = FLOOR_ROWS;
	
	public static final int START = 0;
	public static final int KEY = 1;
	public static final int END = 2;

	public int levelNumber;

	/* Game Structures */
	public Floor[][] floors;
	public Wall[][] hWalls;
	public Wall[][] vWalls;

	public Floor start;
	public Floor key;
	public Floor end;

	public ArrayList<Button> buttons; // Doesn't need to be in xml file, or LevelBuilder
	public ArrayList<Portal> portals; // Doesn't need to be in xml file, or LevelBuilder

	public Level() {
		
		floors = new Floor[FLOOR_COLS][FLOOR_ROWS];
		hWalls = new Wall[HWALL_COLS][HWALL_ROWS];
		vWalls = new Wall[VWALL_COLS][VWALL_ROWS];
		
		setupFloors();
		setupHWalls();
		setupVWalls();

		buttons = new ArrayList<Button>();
		portals = new ArrayList<Portal>();
	}
	
	private void setupFloors() {
		for(int i = 0; i < FLOOR_COLS; i++)
			for(int j = 0; j < FLOOR_ROWS; j++)
				floors[i][j] = new Floor(i,j,Floor.NORMAL);
	}
	
	private void setupHWalls() {
		for(int i = 0; i < HWALL_COLS; i++)
			for(int j = 0; j < HWALL_ROWS; j++)
				if(j == 0 || j == HWALL_ROWS-1)
					hWalls[i][j] = new Wall(i,j,Wall.NORMAL);
				else
					hWalls[i][j] = new Wall(i,j,Wall.NONE);
	}
	
	private void setupVWalls() {
		for(int i = 0; i < VWALL_COLS; i++)
			for(int j = 0; j < VWALL_ROWS; j++)
				if(i == 0 || i == VWALL_COLS-1)
					vWalls[i][j] = new Wall(i,j,Wall.NORMAL);
				else
					vWalls[i][j] = new Wall(i,j,Wall.NONE);
	}

	public void setStart(Floor f) {
		if(f.col < floors.length && f.row < floors[0].length){
			
			start = f;
			
			floors[f.col][f.row] = start; 
		}
	}

	public void setKey(Floor f) {
		if(f.col < floors.length && f.row < floors[0].length){

			key = f;
			
			floors[f.col][f.row] = key;
		}
	}

	public void setEnd(Floor f) {
		if(f.col < floors.length && f.row < floors[0].length){
			
			end = f;
			
			floors[f.col][f.row] = end;
		}
	}
	
	public void setFloor(Floor f) {
		if(f.col < floors.length && f.row < floors[0].length)
			floors[f.col][f.row] = f;
	}
	
	public void setHWall(Wall w) {
		if(w.col < hWalls.length && w.row < hWalls[0].length)
			hWalls[w.col][w.row] = w;
	}
	
	public void setVWall(Wall w) {
		if(w.col < vWalls.length && w.row < vWalls[0].length)		
			vWalls[w.col][w.row] = w;
	}

	public void setButton(Button b) {
		if(b.col < floors.length && b.row < floors[0].length){
			buttons.add(b);

			floors[b.col][b.row] = b;
		}
	}

	public void setPortal(Portal p) {
		if(p.col < floors.length && p.row < floors[0].length){
			portals.add(p);

			floors[p.col][p.row] = p;
		}
	}

	public void setup(boolean startVisible) throws Exception {
		
		// TODO figure out why start,key,end are seperate objects from floor locations
		
		// Setup start, key, end
		if(start == null)
			throw new Exception("You must place a Start Tile.");
		else {
			start.isVisible = startVisible; 
			floors[start.col][start.row] = start;
		}
		
		if(end == null)
			throw new Exception("You must place an End Tile.");
		else if(key == null) {
			//key = start;
			end.isVisible = true;
			floors[end.col][end.row]= end; 
		}
		else {
			end.isVisible = false;
			key.isVisible = true;
			
			floors[end.col][end.row]= end;
			floors[key.col][key.row]= key;
		}
			
		ArrayList<Integer> colors = new ArrayList<Integer>();
		ArrayList<Portal> pcolor;
		ArrayList<Button> bcolor ;
		
		colors.add(Portal.RED);
		colors.add(Portal.BLUE);
		colors.add(Portal.GREEN);
		colors.add(Portal.YELLOW);
		
		boolean portalsFound;
		
		for(int c = 0; c < colors.size(); c++)
		{
			/* get all portals */
			pcolor = new ArrayList<Portal>();
			portalsFound = false;
			for(int p = 0; p < portals.size(); p++){
				if(portals.get(p).color == colors.get(c).intValue())
					pcolor.add(portals.get(p));
			}
			
			// check validity
			if( pcolor.size() != 2 && pcolor.size()!= 0)
				throw new Exception("Portals can only be placed in matching pairs.");
			
			if( pcolor.size() == 2 )
				portalsFound = true;
			
			/* get all buttons */
			bcolor = new ArrayList<Button>();
			for(int b = 0; b < buttons.size(); b++){
				if(buttons.get(b).color == colors.get(c).intValue())
					bcolor.add(buttons.get(b));
			}
			
			// check validity and setup
			if( bcolor.size() > 1)
				throw new Exception("There are too many buttons! How did you do that?");
			
			else if( bcolor.size()==1 && !portalsFound)
				throw new Exception("A button must have two portals of the same color.");
			
			else if( bcolor.size()==1 && portalsFound)
				link(pcolor,bcolor);
			
			else if( bcolor.size()==0 && portalsFound){
				link(pcolor);
			}										
		}
	}
	
	private void link(ArrayList<Portal> pcolor) {
		Portal p1 = pcolor.get(0);
		Portal p2 = pcolor.get(1);
		
		p1.other = p2;
		p2.other = p1;
		
		floors[p1.col][p1.row]=p1;
		floors[p2.col][p2.row]=p2;
		
		pcolor.get(0).isVisible=true;
		pcolor.get(1).isVisible=true;
	}

	private void link(ArrayList<Portal> pcolor, ArrayList<Button> bcolor) {
		Button b = bcolor.get(0);
		b.p1 = pcolor.get(0);
		b.p2 = pcolor.get(1);
		
		link(pcolor);
		
		bcolor.get(0).isVisible=true;
		pcolor.get(0).isVisible=false;
		pcolor.get(1).isVisible=false;
	}

	public void setupPortals() throws Exception {
		
		ArrayList<Integer> colors = new ArrayList<Integer>();
		for(int i = 0; i < buttons.size();i++){
			for(int j = 0; j < colors.size(); j++){
				if (buttons.get(i).color == colors.get(j))
					throw new Exception("too many like buttons");
			}
			colors.add(buttons.get(i).color);
			Portal p1 = buttons.get(i).p1;
			Portal p2 = buttons.get(i).p2;
			buttons.get(i).p1 = (Portal) floors[p1.getCol()][p1.getRow()];
			buttons.get(i).p2 = (Portal) floors[p2.getCol()][p2.getRow()];
		}
		
		ArrayList<Integer[]> pnumber = new ArrayList<Integer[]>();
		for(int i = 0; i < portals.size(); i++){
			boolean found = false;
			for(int j = 0; j < pnumber.size(); j++){
				if (portals.get(i).color == pnumber.get(j)[0]){
					pnumber.get(j)[1]++;
					found = true;
						if(pnumber.get(j)[1]>2)
							throw new Exception("too many portals");
				}

			}
			if(!found){
				Integer[] newColor = new Integer[2];
				newColor[0] = portals.get(i).color;
				newColor[1] = 1;
				pnumber.add(newColor);
			}

			Portal p1 = portals.get(i);
			Portal p2 = (Portal) floors[p1.col][p1.row];
			p1.other = p2;
			p2.other = p1;
		}
		
		
		for(int i = 0; i < pnumber.size(); i++){
			if(pnumber.get(i)[1]<2)
				throw new Exception("not enough portals "+pnumber.get(i)[0]);
		}
		
	}

	public void removePortal(Portal p) {
		for(int i = 0; i < portals.size(); i++ ){
			if(portals.get(i).equals(p))
				portals.remove(i);
		}
		
		// Replace the tile so it doesn't register as a portal later
		floors[p.col][p.row] = new Floor(p.col, p.row, p.type);
	}
	
	public void removeButton(Button b) {
		for(int i = 0; i < buttons.size(); i++ ){
			if(buttons.get(i).equals(b))
				buttons.remove(i);
		}
		
		// Replace the tile so it doesn't register as a button later
		floors[b.col][b.row] = new Floor(b.col, b.row, b.type);
	}

	// builds xml representation of level
	public String toString(){
		String str = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
		str += "<map>\n";
		str += "<start c=\"" + start.col + "\" r=\""+start.row+"\" t=\""+start.type+"\" ></start>\n";
		str += "<end c=\"" + end.col + "\" r=\""+end.row+"\" t=\""+end.type+"\"></end>\n";
		// conditional key
		if(key != null)
			str += "<key c=\"" + key.col + "\" r=\""+key.row+"\" t=\""+key.type+"\"></key>\n";
		
		// floor to xml
		str+= "<floor>\n";
		for(int i = 0; i < floors.length; i++){
		
			for(int j = 0; j < floors[0].length; j++){
				str += floors[i][j].toString() + "\n";
			}
		}
		str+= "</floor>\n";
		
		// vwals to xml
		str+= "<vwall>\n";
		for(int i = 0; i < vWalls.length; i++){
		
			for(int j = 0; j < vWalls[0].length; j++){
				str += vWalls[i][j].toString() + "\n";
			}
		}
		str+= "</vwall>\n";
		
		// hwalls to xml
		str+= "<hwall>\n";
		for(int i = 0; i < hWalls.length; i++){
		
			for(int j = 0; j < hWalls[0].length; j++){
				str += hWalls[i][j].toString() + "\n";
			}
		}
		str+= "</hwall>\n";
		
		str+= "</map>";
		return str;	
		
	}	
}
